/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

public class Server {
    private final static int MAX_NUMBER = 94;
    
    private final static AtomicLong curNum = new AtomicLong(0);

    private ServerSocketChannel serverSocketChannel;

    private Selector selector;
    
    private final ExecutorService exec = Executors.newCachedThreadPool();

    public Server() {
        try {

            selector = Selector.open();

            serverSocketChannel = ServerSocketChannel.open();

            serverSocketChannel.configureBlocking(false);

            InetSocketAddress add = new InetSocketAddress(InetAddress.getLocalHost(), 9999);

            serverSocketChannel.socket().bind(add);

            SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("serverSocketChannel's registered key is : " + key.channel().toString());

            System.out.println();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.startListening();
    }

    private void startListening() {

        System.out.println("Server is listening on: "
        + serverSocketChannel.socket().getInetAddress().getHostAddress() + ":"
        + serverSocketChannel.socket().getLocalPort());

    while (true) {
        try {
            selector.select();

            Iterator<SelectionKey> iter = selector.selectedKeys().iterator();

            while (iter.hasNext()) {
                SelectionKey key = (SelectionKey) iter.next();

                iter.remove();
     
                if (key.isAcceptable()) {
                    System.out.println("Key ready to perform accept() : " + key.channel().toString());

                    SocketChannel client = serverSocketChannel.accept();

                    client.configureBlocking(false);

                    client.register(selector, SelectionKey.OP_WRITE);
                    continue;
                }
                else {
                    exec.execute(new ClientController(key, selector));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    }
    
    public static long next() {
        long i;
        
        while (true) {
            long current = curNum.get();
            long next = (current + 1) % MAX_NUMBER;
            if (curNum.compareAndSet(current, next)) {
                i = next;
                break;
            }
        }
        
        long num = (long) ((Math.pow((1 + Math.sqrt(5))/2, i) -  Math.pow((1 - Math.sqrt(5))/2, i)) / Math.sqrt(5) );
        long res = num;
        return res;
    }
}
